#!/usr/bin/env python
# coding: utf-8

# 导入工具包

import numpy as np  # 矩阵操作
import pandas as pd # SQL数据处理

from sklearn.metrics import mean_squared_error

import matplotlib.pyplot as plt   #画图
import seaborn as sns

from sklearn.model_selection import train_test_split #将数据分割训练数据与测试数据
from sklearn.preprocessing import StandardScaler # 数据标准化
from sklearn.linear_model import LinearRegression 
from sklearn.linear_model import  RidgeCV
from sklearn.linear_model import LassoCV


# 数据探索

# read data
data = pd.read_csv("day.csv")

# 特征工程

# 数据降维
# 去除第一列特征 instant
# 去除第二列特征 dteday
# 根据题目要求，需要预测cnt，而cnt = casual + registered，有数据冗余，故去除casual和registered特征

data_FE = data.drop(['instant', 'dteday', 'casual', 'registered'], axis=1)


# 从原始数据中分离输入特征x和输出y
y = data_FE['cnt'].values
X = data_FE.drop('cnt', axis = 1)

#用于后续显示权重系数对应的特征
columns = X.columns

# 随机采样20%的数据构建测试样本，其余作为训练样本
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=33, test_size=0.2)

#发现各特征差异较大，需要进行数据标准化预处理
#标准化的目的在于避免原始特征值差异过大，导致训练得到的参数权重不归一，无法比较各特征的重要性
# 分别初始化对特征和目标值的标准化器
ss_X = StandardScaler()
ss_y = StandardScaler()

# 分别对训练和测试数据的特征以及目标值进行标准化处理
X_train = ss_X.fit_transform(X_train)
X_test = ss_X.transform(X_test)

#对y做标准化不是必须
#对y标准化的好处是不同问题的w差异不太大，同时正则参数的范围也有限
y_train = ss_y.fit_transform(y_train.reshape(-1, 1))
y_test = ss_y.transform(y_test.reshape(-1, 1))


# # 确定模型类型
# 线性回归ols
# 使用默认配置初始化
lr = LinearRegression()

# 训练模型参数
lr.fit(X_train, y_train)

# 预测
y_test_pred_lr = lr.predict(X_test)
y_train_pred_lr = lr.predict(X_train)

#岭回归／L2正则
#class sklearn.linear_model.RidgeCV(alphas=(0.1, 1.0, 10.0), fit_intercept=True, 
#                                  normalize=False, scoring=None, cv=None, gcv_mode=None, 
#                                  store_cv_values=False)


#设置超参数（正则参数）范围
alphas = [ 0.01, 0.1, 1, 10,100]

#生成一个RidgeCV实例
ridge = RidgeCV(alphas=alphas, cv=5)  

#模型训练
ridge.fit(X_train, y_train)    

#预测
y_test_pred_ridge = ridge.predict(X_test)
y_train_pred_ridge = ridge.predict(X_train)


#### Lasso／L1正则
# class sklearn.linear_model.LassoCV(eps=0.001, n_alphas=100, alphas=None, fit_intercept=True, 
#                                    normalize=False, precompute=’auto’, max_iter=1000, 
#                                    tol=0.0001, copy_X=True, cv=None, verbose=False, n_jobs=1,
#                                    positive=False, random_state=None, selection=’cyclic’)

#生成一个LassoCV实例
lasso = LassoCV(cv=5)  

#训练（内含CV）
lasso.fit(X_train, y_train)  

#测试
y_test_pred_lasso = lasso.predict(X_test)
y_train_pred_lasso = lasso.predict(X_train)

print ('ridge alpha is:', ridge.alpha_)         
print ('lasso alpha is:', lasso.alpha_)

# 看看各特征的权重系数，系数的绝对值大小可视为该特征的重要性
fs = pd.DataFrame({"columns":list(columns), "coef_lr":list((lr.coef_.T)), "coef_ridge":list((ridge.coef_.T)), "coef_lasso":list((lasso.coef_.T))})
print(fs.sort_values(by=['coef_lr'],ascending=False))

# 使用RMSE评价模型在测试集和训练集上的性能，并输出评估结果
print('The RMSE score of LinearRegression on test is', np.sqrt(mean_squared_error(y_test, y_test_pred_lr)))
print('The RMSE score of LinearRegression on train is', np.sqrt(mean_squared_error(y_train, y_train_pred_lr)))

# 评估，使用RMSE评价模型在测试集和训练集上的性能
print('The RMSE score of RidgeCV on test is', np.sqrt(mean_squared_error(y_test, y_test_pred_ridge)))
print('The RMSE score of RidgeCV on train is', np.sqrt(mean_squared_error(y_train, y_train_pred_ridge)))

# 评估，使用RMSE评价模型在测试集和训练集上的性能
print('The RMSE score of LassoCV on test is', np.sqrt(mean_squared_error(y_test, y_test_pred_lasso)))
print('The RMSE score of LassoCV on train is', np.sqrt(mean_squared_error(y_train, y_train_pred_lasso)))


# The result is 
# ridge alpha is: 10.0
# lasso alpha is: 0.001010967178720681
#     coef_lasso                  coef_lr               coef_ridge     columns
# 1     0.531387     [0.5324153075686437]     [0.5230344147953432]          yr
# 0     0.296439    [0.30296485636420933]    [0.28204806382002373]      season
# 8     0.260981    [0.26292545507452547]    [0.25034441111066436]       atemp
# 7     0.224096    [0.22227833793713062]    [0.23420014991985533]        temp
# 4     0.068889    [0.07004159630308626]    [0.06765302057283523]     weekday
# 5     0.043401   [0.044095329630587224]    [0.04372137355139589]  workingday
# 3    -0.028504   [-0.02887596857342884]  [-0.029758458599345977]     holiday
# 9    -0.059513  [-0.060415966935772225]   [-0.06206158987872628]         hum
# 2    -0.079776    [-0.0863561506615993]   [-0.06677593980192022]        mnth
# 10   -0.091277   [-0.09222316307072867]   [-0.09274902100980824]   windspeed
# 6    -0.192979    [-0.1933014064341721]   [-0.18990466056652372]  weathersit
# The RMSE score of LinearRegression on test is 0.42622192010434884
# The RMSE score of LinearRegression on train is 0.4553504584919946
# The RMSE score of RidgeCV on test is 0.4253026602297717
# The RMSE score of RidgeCV on train is 0.4555970198410895
# The RMSE score of LassoCV on test is 0.42601879486568567
# The RMSE score of LassoCV on train is 0.45537126734440353